#include <iostream>
#include <map>
#include <string>
#include "SGL.h"

using namespace std;

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

namespace SGLEngine {

	SGL::SGL()
	{
		this->init();
		DEBUG("Info", "This is SGL default constructor")
		this->device = createDevice(EDT_SOFTWARE, dimension2d<u32>(640, 480), 16, false, false, false, this);
		
	}

	SGL::SGL(SGLEngine::SGLSettings set)
	{
		this->init();
		//this->sge = SGLEvent(this);
		DEBUG("Info", "This is SGL non-default constructor")
		this->device = createDevice((irr::video::E_DRIVER_TYPE)set.DriverType, set.Resolution, set.Bits, set.Fullscreen, set.Stencilbuffer, set.Vsync, this);
	}

	SGL::~SGL()
	{
		if (this->device != NULL)
		{
			DEBUG("Info", "Killing off the Irrlicht device")
			this->device->drop();
			this->device = NULL;
		}
		if (this->Lib2D != NULL)
		{
			DEBUG("Info", "Killing off the Lib2D ptr")
			delete this->Lib2D;
			this->Lib2D = NULL;

		}
		if (this->SGLColor != NULL)
		{
			DEBUG("Info", "Killing off the Lib2D ptr")
			delete this->SGLColor;
			this->SGLColor = NULL;

		}
		if (this->objects2d.size() > 0)
		{
			DEBUG("Info", "Killing 2D user objects!")
			std::map<std::string,CObject2D*>::iterator it;
			for (it = this->objects2d.begin(); it != this->objects2d.end(); it++)
			{
				delete (*it).second;
				(*it).second = NULL;
			}
		}
		if (this->objects3d.size() > 0)
		{
			DEBUG("Info", "Killing 3D user objects!")
			std::map<std::string,CObject3D*>::iterator it;
			for (it = this->objects3d.begin(); it != this->objects3d.end(); it++)
			{
				delete (*it).second;
				(*it).second = NULL;
			}
		}
		if (this->key_events.size() > 0)
		{
			DEBUG("Info", "Killing action objects!");
			for (unsigned int i = 0; i < key_events.size(); i++)
			{
				delete key_events.at(i);
			}
		}
	}

	void SGL::init()
	{
		this->Lib2D = new CLib2D(this->device);
		this->SGLColor = new CSGLColor();
	}

	bool SGL::DeviceIsRunning()
	{
		return this->device->run();
	}
	void SGL::AddObject(CObject2D *obj, std::string name)
	{
		this->objects2d[name] = obj;
	}
	void SGL::AddObject(CObject3D *obj, std::string name)
	{
		this->objects3d[name] = obj;
	}
	/*void SGL::AddObject(void* obj, std::string name)
	{
		CObject2D * tmp = static_cast<CObject2D*>(obj);
		cout << tmp->getType() << endl;
		if (tmp->getType() == "CObject2D")
			this->objects2d[name] = obj;
		else if (tmp->getType() == "CObject3D")
			this->objects3d[name] = obj;
		else
			delete obj; //Make sure there isn't any memory leaks!
	}*/

	void SGL::DrawAll()
	{
		this->device->getSceneManager()->drawAll();
		std::map<std::string,CObject2D*>::iterator it;
		for (it = this->objects2d.begin(); it != this->objects2d.end(); it++)
		{
			//CObject2D * tmp = static_cast<CObject2D *>(it->second);
			if (it->second->start.size() > 0)
			{
				for(unsigned int i = 0; i < it->second->start.size(); i++) 
				{
					this->device->getVideoDriver()->draw2DLine(it->second->start.at(i), it->second->end.at(i), it->second->color.at(i));
				}
			}
			//TODO: Loop through 2D objects and draw lines and images
		}
		
		this->device->getVideoDriver()->endScene();
	}

	void SGL::BeginScene(bool usebackBuffer, bool usezBuffer, irr::video::SColor color)
	{
		this->device->getVideoDriver()->beginScene(usebackBuffer, usezBuffer, color);
	}

	void SGL::BeginScene(SGLSceneSettings set)
	{
		this->device->getVideoDriver()->beginScene(set.usebackBuffer, set.usezBuffer, set.color);
	}

	CSGLColor * SGL::getSGLColor()
	{
		return this->SGLColor;
	}
	CObject2D* SGL::get2DObject(std::string name)
	{
		try {
			return static_cast<CObject2D *>(this->objects2d[name]);
		} catch (...) {
			return NULL;
		}
	}
	void SGL::AddKeyEvent(void* sga)
	{
		this->key_events.push_back(static_cast<SGLAction*>(sga));
	}
	bool SGL::OnEvent(const irr::SEvent &irrevent)
	{
		if (irrevent.EventType == irr::EET_KEY_INPUT_EVENT)
		{
			if (this->key_events.size() > 0)
			{
				for(unsigned int i = 0; i < this->key_events.size(); i++)
				{
					this->key_events.at(i)->Action(irrevent, this);
					return true;
				}
			}
		}
		return false;
	}
}